package com.recharge.service.httpInterFace;

import com.alibaba.fastjson.JSONObject;
import com.recharge.common.result.ResultDO;
import com.recharge.common.result.ResultSupport;
import com.recharge.common.util.Constant;
import com.recharge.common.util.MD5Util;
import com.recharge.common.util.TemplateUtils;
import com.recharge.common.util.http.HttpClientUtil;
import com.recharge.domain.query.OrderStatusQueryDO;
import com.recharge.domain.vo.GoodsChannelDO;
import com.recharge.domain.vo.ProviderApiDO;
import com.recharge.domain.vo.ProviderCallbackDO;
import com.recharge.service.ProviderApiService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.Map.Entry.comparingByKey;

/**
 * 瑞达上游
 */
@Service
public class RuiDaHTTPImpl implements ProviderHTTPService {

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    ProviderApiService providerApiService;

    @Override
    public ResultDO commitOrder(GoodsChannelDO domain) {

        // 参数验证
        if (!verifyCommitParam(domain)) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 请求参数缺失 %s", domain.toString())
                    , "请求参数缺失"
                    , null);
        }
        // 添加存根
        ProviderCallbackDO callbackDO = new ProviderCallbackDO();
        callbackDO.setSerialNumber(domain.getProviderSerialNumber());
        callbackDO.setProviderId(domain.getProviderId());
        callbackDO.setOrderNo(domain.getOrderNo());
        callbackDO.setStatus(Constant.CALL_BACK_PROCESS);
        ResultDO result = providerApiService.addCallback(callbackDO);
        if (!result.isSuccess()) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 订单%s添加回调数据失败", domain.getProviderSerialNumber())
                    , "添加回调存根信息失败"
                    , null);
        }

        //供应商ID
        String userId = domain.getUserId();
        //充值号码
        String rechargeNumber = domain.getRechargeNumber();
        //平台流水号
        String serialNumber = domain.getProviderSerialNumber();
        //商品编号
        String goodsNo = domain.getProviderGoodsNo();
        // 回调地址
        String callbackUrl = domain.getCallback();
        //供应商密钥
        String privateKey = domain.getPrivateKey();

        Map<String, String> param = new LinkedHashMap<>();
        param.put("merchant_id", userId);
        param.put("PhoneNum", rechargeNumber);
        param.put("out_trade_no", serialNumber);
        param.put("productId", goodsNo);
        param.put("callbackUrl", callbackUrl);

        String beforeSign = mapToUrlParam(param, privateKey);
        String afterSign;
        try {
            afterSign = MD5Util.md5(beforeSign).toLowerCase();
        } catch (Exception e) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("渠道商ID: %s HTTP请求参数构建失败", domain.getProviderId())
                    , "HTTP请求参数构建失败"
                    , null);
        }

        String sendParam = "{" +
                "    \"merchant_id\":\"" + userId + "\"," +
                "    \"PhoneNum\":\"" + rechargeNumber + "\"," +
                "    \"out_trade_no\":\"" + serialNumber + "\"," +
                "    \"productId\":\"" + goodsNo + "\"," +
                "    \"callbackUrl\":\"" + callbackUrl + "\"," +
                "    \"sign\":\"" + afterSign + "\"" +
                "}";

        // 发送请求
        logger.warn(String.format("发送POST请求(订单号%s): %s?%s", domain.getProviderSerialNumber(), domain.getRequestUrl(), sendParam));
        String sendResult = HttpClientUtil.doPostJson(domain.getRequestUrl(), sendParam);
        switch (sendResult) {
            case "500":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                        , String.format("订单提交 >> 订单 %s -> 订单提交供货商HTTP请求失败", domain.getProviderSerialNumber())
                        , "HTTP请求失败"
                        , sendResult);
            case "504":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                        , String.format("订单提交 >> 订单 %s -> 订单提交供货商HTTP请求超时", domain.getProviderSerialNumber())
                        , "HTTP请求超时"
                        , sendResult);
            case "":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                        , String.format("订单提交 >> 订单 %s -> 订单提交供货商HTTP请求没有返回信息", domain.getProviderSerialNumber())
                        , "订单提交没有返回信息"
                        , sendResult);
        }
        logger.warn(String.format("订单提交 >> 请求返回信息: 订单号%s -> %s", domain.getProviderSerialNumber(), sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("请求返回结果解析json失败: %s", sendResult));
        }
        if (resultJson.size() == 0) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 提交订单没有返回信息", domain.getProviderSerialNumber())
                    , "没有返回信息"
                    , sendResult);
        }

        String code = null;
        String desc = "";
        try {
            code = resultJson.get("msg_code").toString();
            desc = resultJson.get("Tips").toString();
        } catch (Exception e) {
            logger.debug(String.format("订单提交 >> 获取返回信息失败: 订单号%s -> %s", domain.getProviderSerialNumber(), sendResult));
        }
        if (code == null) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 没有获取到返回状态码", domain.getProviderSerialNumber())
                    , "没有获取到返回状态码"
                    , sendResult);
        }

        String[] array = {"4004", "4005", "4006", "4007", "4010", "4011", "4012", "4013", "4018"};

        if ("201".equals(code)) { //成功
            logger.debug(String.format("订单提交 >> 订单号 %s -> 订单提交成功|%s", domain.getProviderSerialNumber(), desc));
            result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.BUSINESS_RECHARGE_RETURN_STATUS_SUCCESS);
            return result;
        } else if (Arrays.asList(array).contains(code)) { //失败
            return returnFail(true
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 订单号 %s -> 订单失败|%s", domain.getProviderSerialNumber(), desc)
                    , String.format("%s %s", desc, code)
                    , sendResult);
        } else { //未确认
            return returnFail(true
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 订单未知|%s", domain.getProviderSerialNumber(), desc)
                    , String.format("%s %s", desc, code)
                    , sendResult);
        }
    }

    @Override
    public ResultDO backOrder(ProviderApiDO domain, String paramStr, String bodyStr) {
        ResultDO result = new ResultSupport();
        JSONObject jsonObject = null;
        try {
            jsonObject = JSONObject.parseObject(bodyStr);
            logger.debug("订单异步回调 >> " + domain.getProviderNo() + "解析后数据: " + jsonObject.toJSONString());
        } catch (Exception e) {
            logger.debug("订单异步回调 >> " + domain.getProviderNo() + "解析失败:" + paramStr);
        }
        if (jsonObject == null) {
            logger.debug("订单异步回调 >> 收到异步回调,但是没有回调信息");
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            return result;
        }

        //状态码
        String status = "";
        //充值凭证
        String voutcher = "";
        //上游流水号(接口没有提供)
        String orderNo = "";
        //平台流水号
        String serialNum = "";
        //返回签名
        String returnSign = "";
        Map<String, String> map = new LinkedHashMap<>();
        try {
            serialNum = jsonObject.getString("out_trade_no");
            status = jsonObject.getString("status");
            voutcher = jsonObject.getString("OrderNom");

            map.put("merchant_id", jsonObject.getString("merchant_id"));
            map.put("out_trade_no", serialNum);
            map.put("OrderNom", voutcher);
            map.put("phone", jsonObject.getString("phone"));
            map.put("price", jsonObject.getString("price"));
            map.put("status", status);
            map.put("time", jsonObject.getString("time"));
//            merchantId = jsonObject.getString("merchant_id");
//            outTradeNo = jsonObject.getString("out_trade_no");
//            OrderNom = jsonObject.getString("OrderNom");
//            phone = jsonObject.getString("phone");
//            price = jsonObject.getString("price");
//            status = jsonObject.getString("status");
//            time = jsonObject.getString("time");
            returnSign = jsonObject.getString("sign");
        } catch (Exception e) {
            logger.debug("订单异步回调 >> 获取返回结果异常" + e.getMessage());
            result.setSuccess(false);
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            return result;
        }

//        String beforeVerifySign = mapToUrlParam(map, domain.getPrivateKey());
//        String afterVerifySign = "";
//        try {
//            afterVerifySign = MD5Util.md5(beforeVerifySign, 32).toLowerCase();
//        } catch (Exception e) {
//            logger.debug("订单异步回调 >> 订单(" + serialNum + ")验签加密失败" + e.getMessage());
//        }
////        logger.debug("签名验证: after >>"+afterVerifySign);
//        if (!afterVerifySign.equals(returnSign)) {
//            logger.debug("订单异步回调 >> 签名校验: 加密前 >>" + beforeVerifySign);
//            logger.debug(String.format("订单异步回调 >> 订单:%s 签名校验不一致 {本地签名:%s 返回签名:%s }", serialNum, afterVerifySign, returnSign));
//            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
//            return result;
//        }

        //判断订单状态
        if (status.equals("3")) {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 成功 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, voutcher, orderNo, Constant.CALL_BACK_SUCCESS);
        } else if (status.equals("1")){
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 失败 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, "", orderNo, Constant.CALL_BACK_FAIL);
        }else {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 未确认 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, "", orderNo, Constant.CALL_BACK_NUKNOW);
        }

        if (!result.isSuccess()) {
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            return result;
        }

        result.setModel(ResultDO.FIRST_MODEL_KEY, "success");
        return result;
    }

    @Override
    public ResultDO queryOrder(OrderStatusQueryDO domain) {
        ResultDO result = new ResultSupport();
        if (domain.getPrivateKey() == null || domain.getUserId() == null || domain.getSerialNo() == null) {
            result.setSuccess(false);
            logger.debug("查询订单 >> " + domain.getSerialNo() + " 没有查询到供货商信息配置");
            result.setModel(ResultDO.THIRD_MODEL_KEY, "没有查询到供货商信息配置");
            return result;
        }

        Map<String, String> map = new LinkedHashMap<>();
        map.put("merchant_id", domain.getUserId());
        map.put("out_trade_no", domain.getSerialNo());
        String sign;
        try {
            sign = MD5Util.md5(mapToUrlParam(map, domain.getPrivateKey())).toLowerCase();
        } catch (Exception e) {
            logger.debug("查询订单 >> 签名加密失败" + e.getMessage());
            result.setSuccess(false);
            result.setModel(ResultDO.THIRD_MODEL_KEY, "签名加密失败");
            return result;
        }

        String requestParam = "{" +
                "\"merchant_id\":\"" + domain.getUserId() + "\"," +
                "\"out_trade_no\":\"" + domain.getSerialNo() + "\"," +
                "\"sign\":\"" + sign + "\"" +
                "}";

        // 发送请求
        String sendResult = HttpClientUtil.doPostJson(domain.getOrderFindUrl(), requestParam);
        switch (sendResult) {
            case "500":
                logger.debug(String.format("查询订单 >> 订单 %s -> HTTP请求失败|500", domain.getSerialNo()));
                result.setSuccess(false);
                result.setModel(ResultDO.THIRD_MODEL_KEY, "HTTP请求失败");
                return result;
            case "504":
                logger.debug(String.format("查询订单 >> 订单 %s -> HTTP请求超时|504", domain.getSerialNo()));
                result.setSuccess(false);
                result.setModel(ResultDO.THIRD_MODEL_KEY, "HTTP请求超时");
                return result;
            case "":
                logger.debug(String.format("查询订单 >> 订单 %s -> 请求没有返回信息", domain.getSerialNo()));
                result.setSuccess(false);
                result.setModel(ResultDO.THIRD_MODEL_KEY, "请求没有返回信息");
                return result;
        }
        logger.debug(String.format("查询订单 >> 订单查询返回信息: %s -> %s", domain.getSerialNo(), sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("查询订单 >> %s -> 请求返回结果解析JSON失败: %s", domain.getSerialNo(), sendResult));
        }
        if (resultJson.size() == 0) {
            result.setSuccess(false);
            result.setModel(ResultDO.THIRD_MODEL_KEY, "http请求失败");
            logger.debug(String.format("查询订单 >> %s -> 订单查询失败,没有返回信息", domain.getSerialNo()));
            return result;
        }

        String voucher = "";
        String code = "";
        String status = null;
        String success = null;
        String desc = "";
        try {
            if (resultJson.get("state_code") != null){
                code = resultJson.getString("state_code");
            }
            success = resultJson.getString("msg");
            if (resultJson.get("Tips") != null){
                desc = resultJson.getString("Tips");
            }else if (resultJson.get("status") != null){
                desc = resultJson.getString("status");
            }
            status = resultJson.getString("msg_code");
            if (resultJson.get("Un_order") != null) {
                voucher = resultJson.getString("Un_order");
            }
        } catch (Exception e) {
            logger.debug(String.format("查询订单 >> 获取返回信息失败: %s -> %s", domain.getSerialNo(), sendResult));
        }
        if (status == null || success == null) {
            result.setSuccess(false);
            logger.debug(String.format("查询订单 >> %s -> 订单查询失败,没有返回状态码", domain.getSerialNo()));
            result.setModel(ResultDO.THIRD_MODEL_KEY, "http请求失败");
            return result;
        }

        if (success.equals("success")){
            // 3 是成功，1 和 4 是失败， 0 和2 是处理中
            if (code.equals("3")){
                logger.debug(String.format("查询订单 >> 订单 %s -> 订单成功|%s", domain.getSerialNo(), desc));
                result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_SUCCESS);
                result.setModel(ResultDO.SECOND_MODEL_KEY, voucher);
            }else if (code.equals("0") || code.equals("2")){
                logger.debug(String.format("查询订单 >> 订单 %s -> 订单处理中|%s", domain.getSerialNo(), desc));
                result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_PROCESS);
            }else if (code.equals("1") || code.equals("4")){
                logger.debug(String.format("查询订单 >> 订单 %s -> 订单失败|%s", domain.getSerialNo(), desc));
                result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_FAIL);
            }else {
                logger.debug(String.format("查询订单 >> 订单 %s -> 订单未知|%s", domain.getSerialNo(), desc));
                result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_NUKNOW);
            }
        }else {
            result.setSuccess(false);
            logger.debug(String.format("查询订单 >> 订单失败 %s -> %s", domain.getSerialNo(), desc));
            result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_NUKNOW);
        }
        result.setModel(ResultDO.THIRD_MODEL_KEY, desc);
        return result;
    }

    @Override
    public ResultDO queryBalance(ProviderApiDO domain) {
        ResultDO result = new ResultSupport();
        if (domain.getPrivateKey() == null || domain.getUserId() == null) {
            result.setSuccess(false);
            logger.debug("余额查询 >> 没有查询到供货商信息配置");
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }
        String sign = "";
        try {
            sign = MD5Util.md5(String.format("merchant_id=%s%s", domain.getUserId(), domain.getPrivateKey()));
        } catch (Exception e) {
            logger.debug("余额查询 >> 签名加密失败" + e.getMessage());
        }
        String requestParam = "{" +
                "\"merchant_id\":\"" + domain.getUserId() + "\"," +
                "\"sign\":\"" + sign + "\"" +
                "}";

        // 发送请求
        String sendResult = HttpClientUtil.doPostJson(domain.getBalanceFindUrl(), requestParam);
        logger.debug(String.format("余额查询 >> 余额查询返回信息: 供应商账号 %s -> %s", domain.getUserId(), sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("余额查询 >> 请求返回结果解析JSON失败: %s", sendResult));
        }
        if (resultJson.size() == 0) {
            result.setSuccess(false);
            logger.debug(String.format("余额查询 >> 供应商账号: %s -> 余额查询没有返回信息", domain.getUserId()));
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }

        String msg = resultJson.get("status") == null ? "查询失败" : resultJson.getString("status");
        String balance = resultJson.get("balance") == null ? msg : resultJson.getString("balance");
        result.setModel(ResultDO.FIRST_MODEL_KEY, balance);
        return result;

    }

    /**
     * <h2>提交订单返回失败</h2>
     *
     * @param success    是否处理成功
     * @param code       订单状态
     * @param logMessage 失败信息
     * @param message    供货摘要
     * @param entity     返回信息字符串
     * @return FIRST_MODEL_KEY: 订单状态
     * SECOND_MODEL_KEY: 供货摘要
     * THIRD_MODEL_KEY: 上游返回信息字符串
     */
    private ResultDO returnFail(boolean success, int code, String logMessage, String message, String entity) {
        ResultDO result = new ResultSupport();
        result.setSuccess(success);
        result.setModel(ResultDO.FIRST_MODEL_KEY, code);
        result.setModel(ResultDO.SECOND_MODEL_KEY, message);
        result.setModel(ResultDO.THIRD_MODEL_KEY, entity);
        logger.debug(logMessage);
        return result;
    }

    /**
     * <h2>map转换为url字符串</h2>
     * <p>根据key倒序排序拼接</p>
     * @param map
     * @param append
     */
    private String mapToUrlParam(Map<String, String> map, String append) {
        String collect = map.entrySet().stream()
//                .filter(e -> !TemplateUtils.isEmpty(e.getValue()))  //过滤
                .sorted(Collections.reverseOrder(comparingByKey()))  //倒序
                .map(e -> e.getKey() + "=" + e.getValue()) //单个key-value拼接
                .collect(Collectors.joining("&"));//多个拼接
        return collect + append;
    }

    /**
     * 验证提交参数
     *
     * @param domain
     * @return boolean
     */
    private boolean verifyCommitParam(GoodsChannelDO domain) {
        // 密钥
        if (TemplateUtils.isEmpty(domain.getPrivateKey())) {
            return false;
        }
        // 流水号
        if (TemplateUtils.isEmpty(domain.getProviderSerialNumber())) {
            return false;
        }
        // 商户ID
        if (TemplateUtils.isEmpty(domain.getProviderId())) {
            return false;
        }
        // 上游账号
        if (TemplateUtils.isEmpty(domain.getUserId())) {
            return false;
        }
        // 商品编号
        if (TemplateUtils.isEmpty(domain.getProviderGoodsNo())) {
            return false;
        }
        // 充值号码
        if (TemplateUtils.isEmpty(domain.getRechargeNumber())) {
            return false;
        }
        // 回调地址
        if (TemplateUtils.isEmpty(domain.getCallback())) {
            return false;
        }
        // 面值
//        if (TemplateUtils.isEmpty(domain.getAmount())) {
//            return false;
//        }
        // 请求地址
//        if (TemplateUtils.isEmpty(domain.getRequestUrl())) {
//            return false;
//        }

        return true;
    }

}
